package com.hotel.BL;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.EntityName;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
import com.google.appengine.api.datastore.Query.Filter;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;

import data.Block;
import data.Reservation;
import data.passingData.BlockData;

public class BlockLogic extends AbstractBL{
	
	public BlockLogic(HttpServletRequest req,HttpServletResponse resp){
		this.req = req;
		this.resp = resp;
	}
	
	public List<Block> GenerateBlock(long hotelId)
	{
		List<Block> list = new ArrayList<Block>();
		
		Block block;
		if(GetBlock(hotelId,"block1") == null){
			block = new Block();
			block.setHotelId(hotelId);
			block.setTitle("block1");
			list.add(block);
		}
		if(GetBlock(hotelId,"block2") == null){
			block = new Block();
			block.setHotelId(hotelId);
			block.setTitle("block2");
			list.add(block);
		}
		if(GetBlock(hotelId,"block3") == null){
			block = new Block();
			block.setHotelId(hotelId);
			block.setTitle("block3");
			list.add(block);
		}
		
		return list;
	}
	
	public Block GetBlock(long blockId)
	{
		Key key = KeyFactory.createKey(EntityName.Block, blockId);
		try {
			Entity lang = datastore.get(key);
			Block c = new Block();
			c.setEntity(lang);
			return c;
		} catch (EntityNotFoundException e) {
			return null;
		}
	}
		
	
	public Block GetBlock(long hotelId,String title)
	{
		Query q = new Query(EntityName.Block);
		
		Filter filterHotel = new FilterPredicate("hotelId",FilterOperator.EQUAL,hotelId);
		Filter filterStatus = new FilterPredicate("status",FilterOperator.EQUAL,true);
		Filter filterAvaliable = new FilterPredicate("avaliable",FilterOperator.EQUAL,true);
		Filter filterTitle = new FilterPredicate("title",FilterOperator.EQUAL,title);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterStatus, filterAvaliable,filterTitle);
		
		q.setFilter(filter);
		
		return GetBlock(datastore.prepare(q).asSingleEntity());
	}

	//TODO: DELETE WHEN COMPLETE , USE FOR TEST
	public List<Block> GetAllBlockInHotel(long hotelId)
	{
		Query q = new Query(EntityName.Block);
		
		Filter filterHotel = new FilterPredicate("hotelId",FilterOperator.EQUAL,hotelId);

		
		q.setFilter(filterHotel);
		
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
	}
	
	public List<Block> GetAllBlock(long hotelId)
	{
		Query q = new Query(EntityName.Block);
		
		Filter filterHotel = new FilterPredicate("hotelId",FilterOperator.EQUAL,hotelId);
		Filter filterStatus = new FilterPredicate("status",FilterOperator.EQUAL,true);
		Filter filterAvaliable = new FilterPredicate("avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterStatus, filterAvaliable);
		
		q.setFilter(filter);
		
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
	}
	
	public List<BlockData> GetAllBlock4AdminLimit(long hotelId,long offset,long line)
	{
		Query q = new Query(EntityName.Block);
		
		Filter filterHotel = new FilterPredicate("hotelId",FilterOperator.EQUAL,hotelId);
		Filter filterAvaliable = new FilterPredicate("avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterAvaliable);
		
		q.setFilter(filter);
		
		return ReturnData(GetList(datastore.prepare(q).asList(FetchOptions.Builder.withLimit((int) line).offset((int)offset))));
	}
	
	public List<BlockData> ReturnData(List<Block> list){
		List<BlockData> dataList = new ArrayList<BlockData>();
		for(int i=0;i<list.size();i++){
			BlockData data = new BlockData();
			data.setId(list.get(i).getId());
			data.setHotelId(list.get(i).getHotelId());
			data.setTitle(list.get(i).getTitle());
			data.setStatus(list.get(i).getStatus());
			data.setAvaliable(list.get(i).isAvaliable());
			data.setRoomamount(GetRoomAmount(list.get(i).getHotelId(),list.get(i).getId()));
			dataList.add(data);
		}
		return dataList;
	}
	
	public long GetRoomAmount(long hotelId,long id){
		Query q = new Query(EntityName.Room);

		Filter filterHotel = new FilterPredicate("hotelId",
				FilterOperator.EQUAL, hotelId);
		Filter filterBlock = new FilterPredicate("block",
				FilterOperator.EQUAL, String.valueOf(id));
		Filter filterStatus = new FilterPredicate("status",
				FilterOperator.EQUAL, true);
		Filter filterAvaliable = new FilterPredicate("avaliable",
				FilterOperator.EQUAL, true);

		Filter filter = CompositeFilterOperator.and(filterHotel,filterBlock, filterStatus,
				filterAvaliable);

		q.setFilter(filter);

		return datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()).size();
	}
	public List<Block> GetAllBlock4Admin(long hotelId)
	{
		Query q = new Query(EntityName.Block);
		
		Filter filterHotel = new FilterPredicate("hotelId",FilterOperator.EQUAL,hotelId);
		Filter filterAvaliable = new FilterPredicate("avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterAvaliable);
		
		q.setFilter(filter);
		
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
	}
	
	public Block GetBlock(Entity entity)
	{
		if(entity == null) return null;
		Block item = new Block();
		item.setEntity(entity);
		return item;
	}
	
	public List<Block> GetList(List<Entity> entities)
	{
		List<Block> list = new ArrayList<Block>();
		for(Entity e : entities)
		{
			Block a = new Block();
			a.setEntity(e);
			list.add(a);
		}
		return list;
	}

	public Block AddBlock(long hotelId,String title) throws EntityNotFoundException{
		Block b = new Block();
		b.setHotelId(hotelId);
		b.setTitle(title);
		b.setAvaliable(true);
		b.setStatus(true);
		
		Key k = datastore.put(b.getEntity());
		b.setId(k.getId());
		b.setKey(k);

		return b;
	}
	
	public Block EditBlock(long blockId,String title)throws EntityNotFoundException{
		Block b = GetBlock(blockId);
		b.setTitle(title);
		
		Key k = datastore.put(b.getEntity());
		b.setId(k.getId());
		b.setKey(k);

		return b;
	}
	
	public Block DeleteBlock(long blockId) throws EntityNotFoundException{
		Block b = GetBlock(blockId);
		b.setAvaliable(false);
		b.setStatus(false);
		
		Key k = datastore.put(b.getEntity());
		b.setId(k.getId());
		b.setKey(k);

		return b;
	}
	
	public Block ChangeStatus(long blockId) throws EntityNotFoundException{
		
		Block a = GetBlock(blockId);
		if(a.getStatus() == true){
			a.setStatus(false);
		}else if(a.getStatus() == false){
			a.setStatus(true);
		}
		 
		Key k = datastore.put(a.getEntity());
		a.setId(k.getId());
		a.setKey(k);

		return a;
	}
	
	public boolean CanChangeBlock(long hotelId,long blockId){
		Query q = new Query(EntityName.Reservation);
		Date date = new NightAuditLogic(req,resp).ChangeToNightAuditTime(hotelId,new GenericLogic(req,resp).ServerDateTime());
		Filter filterhotelId = new FilterPredicate("hotelId",
				FilterOperator.EQUAL, hotelId);
		Filter filterDate = new FilterPredicate("dateTo",
				FilterOperator.GREATER_THAN_OR_EQUAL, date);
		Filter filter = CompositeFilterOperator.and(filterhotelId, filterDate);
		q.setFilter(filter);
		List<Reservation> list = new ReservationLogic(req,resp).GetList(datastore.prepare(q).asList(
				FetchOptions.Builder.withDefaults()));
		boolean isFoundBlockUse = false;
		for(int i=0;i<list.size();i++){
			if(list.get(i).getRoom().getBlock().getId() == blockId){
				isFoundBlockUse = true;
				break;
			}
		}
		return isFoundBlockUse;
	}
	
	public Block UpdateBlock(Block p)
	{
		Key key = datastore.put(p.getEntity());
		p.setId(key.getId());
		p.setKey(key);
		return p;
//		Block updatedP = GetBlock(p.getId());
//		updatedP = p;
//		Key key = datastore.put(updatedP.getEntity());
//		updatedP.setId(key.getId());
//		return updatedP;
	}
}
